const gulp = require('gulp');
const config = require('./config');
const path = require('path');
const sass = require('gulp-sass');
const packageImporter = require('node-sass-package-importer');
const postcss = require('gulp-postcss');
const sourcemaps = require('gulp-sourcemaps');
const autoprefixer = require('autoprefixer');
const transform = require('postcss-transform-shortcut');
const pug = require("gulp-pug");
const selectornot = require("postcss-selector-not");
const cssImageSet = require('postcss-image-set-polyfill');
const quantityQueries = require('postcss-quantity-queries');
const postcssPpx2rpx = require('./ppx2rpx');
const cssnano = require('cssnano');
const replace = require('gulp-replace');
const yargs = require('yargs');
const _ = require('lodash');

var csass = require('node-sass');
console.log(csass.info);

// gulp.task('sass', function () {
//     let browsers = ['IE >= 8', 'iOS 7', 'Firefox > 30'];
//
//     if (config.browsers) {
//         browsers = config.browsers;
//     }
//
//     let plugins = [
//         quantityQueries(),
//         cssImageSet(),
//         selectornot(),
//         autoprefixer({
//             browsers: browsers
//         }),
//         cssnano({
//         }),
//     ];
//     let ret = gulp.src(config.sasspath)
//     // .pipe(sourcemaps.init())
//         .pipe(sass({
//             data: '',
//             importer: packageImporter()
//         }).on('error', sass.logError))
//         .pipe(postcss(plugins))
//         .pipe(replace('Symbol(GANG)', '\\'))
//     // .pipe(sourcemaps.write())
//
//     if (config.sassresolve) {
//         ret = config.sassresolve(ret);
//     }
//
//     ret.pipe(gulp.dest(config.csspath))
// });
//
// gulp.task('sass:watch', function () {
//     gulp.watch(config.sasspath, ['sass']);
// });


const browserify = require('gulp-browserify');
const watchify = require('watchify');
const through = require('through2')
const babelify = require('babelify');
const source = require('vinyl-source-stream');
const buffer = require('vinyl-buffer');
const merge = require('utils-merge');
const gutil = require('gulp-util');
const chalk = require('chalk');
const babel = require('gulp-babel');
const watch = require('node-watch')
const twig = require('gulp-twig');
const short = require('postcss-short');
const fileinclude = require('gulp-file-include');
const rename = require("gulp-rename");
const json5 = require("gulp-json5");
const concat = require('gulp-concat');
const gap = require('gulp-append-prepend');
const fs = require("fs");
const exec = require('child_process').exec;

var obj =  require.cache[Object.keys(require.cache)
    .find((x) => x.indexOf('gulp-util/index') >= 0)];

if (obj && obj.exports) {
    obj.exports.colors.stripColor = require('strip-ansi');
}


function map_error(err) {
    if (err.fileName) {
        // regular error
        gutil.log(chalk.red(err.name)
            + ': '
            + chalk.yellow(err.fileName.replace(__dirname + '/src/js/', ''))
            + ': '
            + 'Line '
            + chalk.magenta(err.lineNumber)
            + ' & '
            + 'Column '
            + chalk.magenta(err.columnNumber || err.column)
            + ': '
            + chalk.blue(err.description))
    } else {
        // browserify error..
        gutil.log(chalk.red(err.name)
            + ': '
            + chalk.yellow(err.message))
    }

    this.end()
}

var file = config.espath;
var babelOptions = {
    presets: ["es2015-loose"],
    plugins: [
        "transform-custom-element-classes"
    ]
};

let defaultscriptoption = {
    debug: true
};

let scriptcompileoption = Object.assign(defaultscriptoption, config.compileoptions);

gulp.task('script:watch', function () {
    var args = merge(watchify.args, scriptcompileoption)
    var bundler = watchify(browserify(file, args))
        .transform(babelify, babelOptions)

    console.log("build file mjs");

    bundle_js(bundler);

    bundler.on('update', function () {
        bundle_js(bundler)
    })
});

function bundle_js(bundler) {
    let ret = bundler.bundle()
        .on('error', map_error)
        .pipe(source(`index.js`))
        .pipe(buffer())
        .pipe( gulp.dest(path.dirname(file)) )

    if (config.nosourcemap) {
        return ret.pipe(sourcemaps.init({ loadMaps: false }))
            .pipe(sourcemaps.write('.'))
            .pipe(gulp.dest(config.jspath))
    } else {
        return ret;
    }
}

gulp.task('script', function () {
    browserify(file, {})
    .transform(babelify, {})
    .pipe(gulp.dest(path.dirname(src)))   
});

var babelComileoptions = {
    presets: [
        ["es2015", {
            loose: true
        }]
    ],
    plugins: [
        "transform-custom-element-classes",
        "transform-es3-property-literals",
        "transform-es3-member-expression-literals"
    ]
};

var commonPlugins =  [
    ["transform-class-properties", { "spec": true }],
    ["transform-object-rest-spread", { "useBuiltIns": true }],
    ["transform-runtime", {
      "helpers": false,
      "polyfill": false,
      "regenerator": true,
      "moduleName": "babel-runtime"
    }]
];

let runWebpack = _.throttle(function () {
    console.log("run webpack");
    exec("webpack --config ./webpack.config.js", function(err, stdout, stderr) {
        if (err) {console.log(err); return}
        console.log(stdout);
        console.log(stderr);
    });
}, 700);

let shortConfig = {
    position: {
        skip: "_"
    },
    spacing: {
        skip: "_"
    },
    border: {
        skip: "_"
    }
};

let customTwig = {
    data: {},
    extend: function (Twig) {

    },
    functions: [
        {
            name: "v",
            func: function (args) {
                return `{{ ${args} }}`;
            },
            name: "attr",
            func: function (obj) {
                let a = "";
                if (obj && typeof obj === 'object') {
                    for (let [key, value] of Object.entries(obj)) {
                        if (key !== "_keys") {
                           a = a + `${key}='${value}' `;
                        }
                    }
                }
                return a;
            }
        }
    ]
};

function handleFilecompile(evt, src) {
    let paths = src.split(path.sep);
    if (ig.ignores(src)) {
        return "";
    }
    if (config && config.watchrelations) {
        for (let relationkey in config.watchrelations) {
            if (src.indexOf(relationkey) > -1) {
                src = config.watchrelations[relationkey];
                paths = src.split(path.sep);
            }
        }
    }

    const postcssmixins = require('postcss-mixins');
    if ( src.indexOf("___jb_") < 0 && !paths[paths.length - 1].startsWith(".") && !paths[paths.length - 1].startsWith("_") ) {
        if (_.find(["mjs","es6","es7","twig","scss","postcss","mdx","axml", "pug", "json5","wxsc","umd"], function (v) {
                return paths[paths.length - 1].endsWith(v);
            })) {
            console.log("start build:", src);
            let ret = gulp.src(src);
            ret = ret.pipe(fileinclude({
                prefix: '@@',
                basepath: '@file'
            }))
            if (src.endsWith("mjs") ) {
                ret = ret
                    .pipe(babel(babelComileoptions))
                    .pipe(browserify({
                    }))
            }
            if (src.endsWith("es6") ) {
                ret = ret
                    .pipe(babel(babelComileoptions))
            }
            if (src.endsWith("es7") ) {
                let es7config = Object.assign({
                    babel: {
                        presets: [
                            [
                                "env",
                                {
                                    "targets": {
                                        "browsers": ["ios > 7"]
                                    }
                                }
                            ]
                        ],
                        "plugins": commonPlugins
                    }
                }, config.es7config ? config.es7config : {})
                ret = ret
                    .pipe(babel(es7config.babel))
            }
            if (src.endsWith("umd")) {
                let modulename = paths[paths.length - 1].split(".")[0];
                console.log(modulename);
                ret = ret
                    .pipe(
                        babel({
                            presets: [
                                [
                                    "env",
                                    {
                                        "targets": {
                                            "browsers": ["ios > 7"]
                                        }
                                    }
                                ]
                            ],
                            "plugins": commonPlugins
                        })
                    )
                    .pipe(
                        browserify({
                            standalone: modulename
                        })
                    )
            }
            if (src.endsWith("twig") ) {
                ret = ret
                    .pipe(twig({
                    }))
            }
            if (src.endsWith("pug") ) {
                ret = ret
                    .pipe(pug({
                    }))
                    .pipe(rename(function (path) {
                        path.extname = "." + (config.pug ? config.pug : 'html');
                    }))
            }
            if (src.endsWith("wxs") ) {
            }
            if (src.endsWith("axml")) {
                ret = ret
                    .pipe(twig(customTwig))
                    .pipe(replace(/<\/?[(\w)\s=\{\}"/.':;#-\/\?]+>/gi, function (match, $1) {
                        return match.replace("div", "view");
                    }))
                    .pipe(rename(function (path) {
                        path.extname = ".wxml";
                    }));
            }
            if (src.endsWith("json5")) {
                ret = ret
                    .pipe(json5({
                        beautify: true
                    }))
            }
            if (src.endsWith("mdx") ) {
                let mdxconfigPath = paths.slice(0, paths.length - 1).concat(["mdx.config.js"]).join(path.sep);
                let isMdxConfigFileExists = fs.existsSync(mdxconfigPath)
                ret = ret
                    .pipe(rename(function (path) {
                        path.extname = ".md";
                    }))

                if (isMdxConfigFileExists) {
                    ret = require(mdxconfigPath)(ret, replace, {});
                }
            }
            if (src.endsWith("scss") ) {
                let browsers = ['IE >= 8', 'iOS 7', 'Firefox > 30'];
                let plugins = [
                    quantityQueries(),
                    cssImageSet(),
                    selectornot(),
                    short({
                        position: {
                            skip: "_"
                        }
                    }),
                    autoprefixer({
                        browsers: browsers
                    }),
                    // cssnano({
                    // }),
                ];
                ret = ret
                    .pipe(sass({
                        data: '',
                        importer: packageImporter(),
                        sourceComments: 'normal'
                    }).on('error', sass.logError))
                    .pipe(postcss(plugins))
                    .pipe(replace('Symbol(GANG)', '\\'))
            }
            if (src.endsWith("wxsc") ) {
                let browsers = ['iOS 7'];
                let filter =  require('postcss-filter-rules');

                let plugins = [
                    postcssmixins(),
                    quantityQueries(),
                    cssImageSet(),
                    selectornot(),
                    short(shortConfig),
                    transform(),
                    postcssPpx2rpx({
                        multiple: 2
                    }),
                    autoprefixer({
                        browsers: browsers
                    }),
                ];
                ret = ret
                    .pipe(sass({
                        data: '',
                        importer: packageImporter(),
                        // sourceComments: 'normal'
                    }).on('error', sass.logError))
                    .pipe(postcss(plugins))

                if (fs.existsSync(path.join(src + ".native", "header.wxss"))) {
                    ret = ret.pipe(gap.prependFile(path.join(src + ".native", "header.wxss")))
                }

                if (fs.existsSync(path.join(src + ".native", "footer.wxss"))) {
                    ret = ret.pipe(gap.appendFile(path.join(src + ".native", "footer.wxss")))
                }

                ret = ret.pipe(rename(function(path) {
                    path.extname = ".wxss";
                }))
                    .pipe(replace('Symbol(GANG)', '\\'))
            }
            if (src.endsWith("postcss") ) {
                ret = ret
                    .pipe(postcss(plugins))
                    .pipe(replace('Symbol(GANG)', '\\'))
            }
            if (ret && ret.pipe) {
                let destpath = path.dirname(src);
                if (config && config.handleDestPath) {
                    destpath = config.handleDestPath(destpath);
                }
                if (!destpath) {
                    return;
                } else {
                    ret
                        .pipe(
                            through.obj(function (chunk, enc, cb) {
                                console.log("build end " + chunk.path )
                                cb(null, chunk)
                            })
                        )
                        .pipe(gulp.dest(destpath))
                }
                // console.log("build end", destpath);
                // ret.pipe(
                //     through.obj(function (chunk, enc, cb) {
                //         console.log("build end " + chunk.path )
                //         if (chunk.path.indexOf("webcomponents") > - 1) {
                //             runWebpack();
                //         }
                //         cb(null, chunk)
                //     })
                // ).pipe(destpath)


                // if (src.endsWith("mjs") ) {
                //     gulp.src(src)
                //         .pipe(babel({
                //             presets: [
                //                 [
                //                     "env",
                //                     {
                //                         "targets": {
                //                             "browsers": ["ie > 8"]
                //                         }
                //                     }
                //                 ]
                //             ]
                //         }))
                //         .pipe(rename(function(path) {
                //             path.basename += ".common";
                //         }))
                //         .pipe(destpath)
                // }
            }
        }
    }
}

const ignore = require('ignore')
let ig = ignore().add(['node_modules', '.git', 'build', '.idea', 'dist']);

if (yargs.argv && yargs.argv.nowatch) {
    const walkSync = require('walk-sync');
    // console.log(config.watchPath);
    let paths = walkSync(path.join(config.watchPath), { ignore: ['vendors'] });
    let promises = [];
    let r = path.join(config.watchPath);
    paths.filter((v)=> {
        // return v.endsWith("com.wxsc");
        return true;
    }).forEach(function (v, i) {
        // console.log(paths.length);
        promises.push(new Promise(function (resolve, reject) {
            setTimeout(function () {
                // console.log("build ", path.join(r, v), i);
                handleFilecompile({}, path.join(r, v));
                resolve();
            }, 30 * i);
        }))
    })
    // console.log(promises);
    Promise.all(promises);
} else {
    console.log("watch " + config.watchPath);
    watch(config.watchPath, { recursive: true }, handleFilecompile);
    for (let relationkey in config.watchrelations) {
        gulp.watch(path.join(__dirname, relationkey), function () {
            let src = path.join(__dirname, config.watchrelations[relationkey]);
            handleFilecompile({}, src);
        });
    }
}

